import React, { useEffect, useState } from 'react';
import { Controller, useForm } from 'react-hook-form';
import { ErrorMessage } from '@hookform/error-message';
import {
  Box,
  CardBase,
  FormStatusMessage,
  Grid,
  GridItem,
  Input,
  MainButton,
  makeToast,
  NumberInput,
  Text,
  Tooltip,
} from '@nova-hf/ui';
import { emailValidate } from 'beta/utils/helpers';
import { useRouter } from 'next/router';
import {
  useAddCustomerMutation,
  useChangeServiceUserMutation,
  useCustomerNameByNationalIdLazyQuery,
  useOrganizationNameLazyQuery,
  usePersonNameLazyQuery,
  useServiceQuery,
} from 'typings/graphql';
import { useTranslation } from 'utils/i18n';

import { StillingarLoader } from '../components/StillingarLoader';

type UserSettingsForm = {
  nationalId: string;
  email: string;
  name: string;
};

export const UserSettingsContainer = () => {
  const { t } = useTranslation('stillingar');
  const router = useRouter();

  const { control, watch, setError, clearErrors, setValue } = useForm<UserSettingsForm>({
    defaultValues: {
      nationalId: '',
      name: '',
      email: '',
    },
    delayError: 500,
    mode: 'onChange',
  });

  const { nationalId, email, name } = watch();

  const { data, loading, error } = useServiceQuery({
    variables: {
      serviceId: (router.query.serviceId as string) ?? '',
    },
  });

  const service = data?.service;

  const [isNewCustomer, setIsNewCustomer] = useState(false);
  const [isValidNationalId, setIsValidNationalId] = useState(true);
  const [isEdited, setIsEdited] = useState(false);
  const [changeServiceError, setChangeServiceError] = useState('');

  const [changeServiceUser, { loading: changeServiceLoading }] = useChangeServiceUserMutation();
  const [addCustomer, { loading: addCustomerLoading }] = useAddCustomerMutation();

  const [getPersonName, { loading: loadingPersonName }] = usePersonNameLazyQuery({
    onCompleted(data) {
      if (data.person?.name) {
        const personName: string = data.person.name;
        setValue('name', personName);
        setIsNewCustomer(true);
        clearErrors();
        setIsValidNationalId(true);
      } else {
        handleFailedToGetNationalId();
      }
    },
    onError(error) {
      if (error) {
        handleFailedToGetNationalId();
        if (error instanceof Error) makeToast.danger(t('userSection.errorTitle'), error.message);
      }
    },
  });

  const [getOrganizationName, { loading: loadingOrganizationName }] = useOrganizationNameLazyQuery({
    onCompleted(data) {
      if (data.organization?.name) {
        const orgName: string = data.organization.name;
        setValue('name', orgName);
        setIsNewCustomer(true);
        clearErrors();
        setIsValidNationalId(true);
      } else {
        handleFailedToGetNationalId();
      }
    },
    onError(error) {
      if (error) {
        handleFailedToGetNationalId();
        if (error instanceof Error) makeToast.danger(t('userSection.errorTitle'), error.message);
      }
    },
  });

  const [getCustomer, { loading: loadingCustomer }] = useCustomerNameByNationalIdLazyQuery({
    onCompleted(data) {
      if (data.customerByNationalId?.nationalId) {
        const customerNatId: string = data.customerByNationalId?.nationalId ?? '';
        const customerName: string = data.customerByNationalId?.name ?? '';
        const customerEmail: string = data.customerByNationalId?.email ?? '';
        setValue('nationalId', customerNatId);
        setValue('name', customerName);
        setValue('email', customerEmail);
        setIsValidNationalId(true);
      } else {
        handleFailedToGetNationalId();
      }
    },
    onError(error) {
      if (error) {
        if (parseInt(nationalId[0]) > 3) {
          try {
            getOrganizationName({
              variables: {
                input: {
                  nationalId: nationalId,
                },
              },
            });
          } catch (error) {
            handleFailedToGetNationalId();
            if (error instanceof Error)
              makeToast.danger(t('userSection.errorTitle'), error.message);
          }
        } else {
          try {
            getPersonName({
              variables: {
                input: {
                  nationalId: nationalId,
                },
              },
            });
          } catch (error) {
            handleFailedToGetNationalId();
            if (error instanceof Error)
              makeToast.danger(t('userSection.errorTitle'), error.message);
          }
        }
      }
    },
  });

  const resetFieldsToOriginal = () => {
    setIsEdited(false);
    if (service?.user?.nationalId) {
      setValue('nationalId', service.user.nationalId);
      setValue('name', service?.user?.name ?? '');
      setValue('email', service.user.email ?? '');
      setIsValidNationalId(true);
      setIsEdited(false);
    }
  };

  const handleFailedToGetNationalId = () => {
    setValue('name', '');
    setError('nationalId', {
      message: t('userSection.nationalIdNotFound'),
    });
    setIsValidNationalId(false);
  };

  useEffect(() => {
    if (service?.user?.nationalId) {
      resetFieldsToOriginal();
    }
  }, [service]);

  useEffect(() => {
    setValue('name', '');
    setValue('email', '');
    setIsEdited(false);
    if (nationalId.length === 10 && nationalId !== data?.service.user?.nationalId) {
      setIsEdited(true);
      try {
        getCustomer({
          variables: {
            input: {
              nationalId: nationalId,
            },
          },
        });
      } catch (error) {
        handleFailedToGetNationalId();
        if (error instanceof Error) makeToast.danger(t('userSection.errorTitle'), error.message);
      }
    } else if (nationalId.length === 10 && nationalId === data?.service.user?.nationalId) {
      resetFieldsToOriginal();
    }
  }, [nationalId]);

  const handleCreateNewCustomer = async () => {
    try {
      const { data: addCustomerData } = await addCustomer({
        variables: {
          input: {
            nationalId: nationalId,
            email: email,
          },
        },
      });
      if (addCustomerData?.addCustomer.customer.id) {
        const id = addCustomerData.addCustomer.customer.id;
        if (id) await handleChangeService();
      } else if (addCustomerData?.addCustomer.error) {
        if (addCustomerData?.addCustomer.error instanceof Error) {
          makeToast.danger(t('userSection.errorTitle'), addCustomerData?.addCustomer.error.message);
        }
      }
    } catch (error) {
      if (error instanceof Error) {
        makeToast.danger(t('userSection.errorTitle'), error.message);
      }
    }
  };

  const handleChangeService = async () => {
    try {
      const { data } = await changeServiceUser({
        variables: {
          input: {
            serviceId: (router.query.serviceId as string) ?? '',
            newUserNationalId: nationalId,
            oldUserNationalId: service?.user?.nationalId || '',
            changeDate: new Date(),
          },
        },
      });

      if (data?.changeServiceUser?.service?.id) {
        router.replace({
          query: { ...router.query, serviceId: data?.changeServiceUser.service.id },
        });
      }

      if (data?.changeServiceUser?.service?.user) {
        clearErrors();
        setValue('nationalId', data.changeServiceUser.service.user.nationalId ?? '');
        setValue('name', data.changeServiceUser.service.user.name ?? '');
        setValue('email', data.changeServiceUser.service.user.email ?? '');
        makeToast.success(
          t('userSection.changeUserSuccessTitle'),
          t('userSection.changeUserSuccessDescription'),
        );
      }
      if (data?.changeServiceUser?.error) {
        setChangeServiceError(
          data?.changeServiceUser?.error.message ?? t('userSection.errorTitle'),
        );
      }
    } catch (e) {
      if (e instanceof Error) {
        setChangeServiceError(e.message);
      }
    }
  };

  const onClickChangeServiceUser = async () => {
    if (isNewCustomer) {
      await handleCreateNewCustomer();
    } else {
      await handleChangeService();
    }
  };

  const onClickCancelChangeServiceUser = () => {
    const userNationalId: string = service?.user?.nationalId ?? '';
    const userName: string = service?.user?.name ?? '';
    setValue('nationalId', userNationalId);
    setValue('name', userName);
  };

  if (!service || error) return null;
  if (loading) return <StillingarLoader />;

  return (
    <>
      <Box marginBottom={[5, 10]}>
        <Text variant="pMediumBold">{t('userSection.updateUserEyebrow')}</Text>
        <Text variant="pMediumRegular">{t('userSection.updateUserDescription')}</Text>
      </Box>
      <Grid gridTemplate={{ sm: 4, md: 8 }}>
        <GridItem gridColumn={{ sm: 'span4' }}>
          <Controller
            name={'nationalId'}
            control={control}
            rules={{
              minLength: {
                value: 10,
                message: t('userSection.nationalIdMinLenError'),
              },
              maxLength: {
                value: 10,
                message: t('userSection.nationalIdMaxLenError'),
              },
            }}
            render={({ field, formState: { errors } }) => {
              const { value, name, ref, ...rest } = field;
              return (
                <>
                  <NumberInput
                    id="nationalId"
                    name={name}
                    numberType="nationalId"
                    label={t('userSection.nationalIdLabel')}
                    value={value}
                    ref={ref}
                    disabled={
                      addCustomerLoading ||
                      changeServiceLoading ||
                      loadingPersonName ||
                      loadingOrganizationName ||
                      loadingCustomer
                    }
                    {...rest}
                  />
                  <ErrorMessage
                    errors={errors}
                    name={name}
                    render={({ message }) => <FormStatusMessage message={message} status="error" />}
                  />
                  {(loadingPersonName || loadingOrganizationName || loadingCustomer) && (
                    <FormStatusMessage
                      message={t('userSection.fetchingNationalIdMessage')}
                      status="loading"
                    />
                  )}
                </>
              );
            }}
          />
        </GridItem>
        <GridItem gridColumn={{ sm: 'span4' }}>
          <Input
            id="name"
            label={t('userSection.nameLabel')}
            name="service"
            value={name}
            disabled
          />
        </GridItem>

        <GridItem gridColumn={{ sm: 'span3', md: 'span7' }}>
          <Controller
            name="email"
            control={control}
            rules={{
              validate: {
                email: (value) => {
                  return emailValidate(value);
                },
              },
            }}
            render={({ field, formState: { errors } }) => {
              const { value, name, ref, ...rest } = field;
              return (
                <>
                  <Input
                    id="email"
                    label={t('userSection.emailLabel')}
                    autoComplete="off"
                    ref={ref}
                    name={name}
                    value={value}
                    disabled={
                      addCustomerLoading ||
                      changeServiceLoading ||
                      loadingPersonName ||
                      loadingOrganizationName ||
                      loadingCustomer
                    }
                    {...rest}
                  />
                  <ErrorMessage
                    errors={errors}
                    name={name}
                    render={({ message }) => (
                      <FormStatusMessage
                        message={
                          errors.email?.type === 'email'
                            ? t('userSection.emailInvalidMessage')
                            : message
                        }
                        status="error"
                      />
                    )}
                  />
                  {!!changeServiceError && (
                    <FormStatusMessage status="error" message={changeServiceError} />
                  )}
                </>
              );
            }}
          />
        </GridItem>
        <GridItem gridColumn={{ sm: 'span1' }}>
          <Box display="flex" placeItems="center" height="100%">
            <Tooltip shouldShowOnHover>
              <CardBase borderColor="grey200" dottedShadow="none" hasBorder>
                <Box padding={2}>
                  <Text marginBottom={1} variant="pMediumBold">
                    {t('userSection.emailTooltipTitle')}
                  </Text>
                  <Text marginBottom={1} variant="pXSmallRegular">
                    {t('userSection.emailTooltipDescription')}
                  </Text>
                </Box>
              </CardBase>
            </Tooltip>
          </Box>
        </GridItem>
        <>
          <GridItem gridColumn={{ sm: 'span4', md: '3/5' }}>
            <MainButton
              colorScheme="white"
              text={t('userSection.changeUserCancelButton')}
              onClick={onClickCancelChangeServiceUser}
              dottedShadow="none"
              isDisabled={
                addCustomerLoading ||
                changeServiceLoading ||
                loadingPersonName ||
                loadingOrganizationName ||
                loadingCustomer
              }
            />
          </GridItem>
          <GridItem gridColumn={{ sm: 'span4', md: '6/8' }}>
            <MainButton
              text={t('userSection.changeUserButton')}
              onClick={onClickChangeServiceUser}
              dottedShadow="none"
              isLoading={addCustomerLoading || changeServiceLoading}
              isDisabled={
                !isEdited ||
                !isValidNationalId ||
                loadingPersonName ||
                loadingOrganizationName ||
                loadingCustomer
              }
            />
          </GridItem>
        </>
      </Grid>
    </>
  );
};
